import java.io.*;
import com.exploringxml.xml.*;
import java.util.*;
import java.lang.String;

public class AdventureLoader {
	
    /*
	 * Method for Loading the dummy adventure
	 */    
    public static Adventure load() {
		Adventure adv = new Adventure();
		
		createDummyAdventure(adv);
		return adv;
    }
	
    
    /*
	 * Method for Loading an adventure file
	 */    
    public static Adventure load(InputStream adv_is) {
		Adventure adv = new Adventure();
		
		//createDummyAdventure(adv);
		parseAdventureXML(adv_is, adv);
		return adv;
    }
	
    public static void parseAdventureXML(InputStream ist, Adventure av)
    {
    	StringBuffer sb = new StringBuffer();
        int c;
        try
			{
				while ((c = ist.read()) != -1) {
					sb.append((char)c);
				}
			}
        catch(IOException e)
			{
				System.out.println("IOException when reading adventure xml...");
			}
		
        String xmlString = sb.toString();
        
        //xmlString.replaceAll("\t", "");
        // parse string and build document tree
        Node root = new Xparse().parse(xmlString);
        //System.out.println("XML received: " + sb.toString());
        int occur[] = {1};
        Node doc = root.find("adventure", occur);
        if (doc == null)
			{
				System.out.println("<adventure> missing; is this an adventure file?");
			}
        else
			{
				//String advTitle = doc.name;
				//System.out.println("Adventure: " + advTitle);
				readAdventure(doc,av);
			}
    }
    
    public static void readAdventure(Node advNode, Adventure adv)
    {
    	int occur[] = {1};
        Node info = advNode.find("info", occur);
        Node ralley = advNode.find("ralley", occur);
        
        if (info == null || ralley == null)
		{
			System.out.println("<info>, or <ralley> missing: not a valid adventure file!");
		}
        else
		{
			readInfo(info, adv);
			readRalley(ralley, adv);
		}
    }
    
    public static void readInfo(Node infoNode, Adventure adv)
    {
    	String tmp = childContentByName(infoNode, "name");
    	if(tmp != "")
    	{
    		adv.setTitle(tmp);
    	}
    	
    	tmp = childContentByName(infoNode, "author");
    	if(tmp != "")
    	{
    		adv.setAuthor(tmp);
    	}
    	
    	tmp = childContentByName(infoNode, "place");
    	if(tmp != "")
    	{
    		adv.setPlace(tmp);
    	}
    	
    	tmp = childContentByName(infoNode, "description");
    	if(tmp != "")
    	{
    		adv.setDescription(tmp);
    	}
    	
    	//@TODO: Still need to read results part...
    }
    
    public static String childContentByName(Node parentNode, String childName)
    {
    	return childContentByName(parentNode, childName, 1);
    }
    
    public static String childContentByName(Node parentNode, String childName, int occurence)
    {
    	int occur[] = {occurence};
    	
    	Node tmp = parentNode.find(childName, occur);
        if (tmp != null)
        {
        	return tmp.getCharacters();
        }
    	
    	return "";
    }
    
    public static String killTabs(String in)
    {
    	String outString = "";
    	
    	in.trim();
    	
    	for(int i = 0; i < in.length(); i++)
    	{
    		if(in.charAt(i) != '\t' )
    		{
    			outString = outString + in.charAt(i);
    		}
    	}
    	
    	outString = outString.trim();
    	
    	if((outString.charAt(0) == '\n' || outString.charAt(0) == '\f' || outString.charAt(0) == '\r') && outString.length() > 1)
    	{
    		//System.out.println("removed beginning linebreak");
    		outString = outString.substring(1);
    	}
    	
    	outString = outString.trim();
    	
    	if(outString.endsWith("\n") || outString.endsWith("\f") || outString.endsWith("\r"))
    	{
    		//System.out.println("removed end linebreak");
    		outString = outString.substring(0, outString.length() - 2);
    	}
    	
    	outString = outString.trim();
    	
    	//System.out.println("Cleaned String: " + outString);
    	return outString; 
    }
    
    public static void readRalley(Node ralleyNode, Adventure adv)
    {	
    	Hashtable allNodes = new Hashtable();
    	
    	int occur[] = {1};
    	
    	while(ralleyNode.find("node", occur) != null)
    	{
    		makeGameNode(ralleyNode.find("node", occur), adv, allNodes);
    		occur[0]++;
    	}
    	
    	//System.out.println("All nodes parsed... beginning to link...");
    	
    	occur[0] = 1;
    	
    	while(ralleyNode.find("node", occur) != null)
    	{
    		linkGameNode(ralleyNode.find("node", occur), adv, allNodes);
    		occur[0]++;
    		//System.out.println("round " + occur[0]);
    	}
    }
    
    public static void linkGameNode(Node xmlNode, Adventure adv, Hashtable allNodes)
    {
    	GameNode tmpNode = (GameNode)allNodes.get(xmlNode.attributes.get("id"));
    	//System.out.println("looked up node: " + tmpNode.getid());
    	
    	int occur[] = {1};
    	
    	Node answers = xmlNode.find("answers", occur);
    	
		while(answers.find("solution", occur) != null)
		{
			//System.out.println("trying to link to: " + answers.find("solution", occur).attributes.get("t_id"));
			Solution tmpSolution = new Solution(childContentByName(answers, "solution", occur[0]));
			
			
			if(answers.find("solution", occur).attributes.get("t_id") != null)
			{
				tmpSolution.setTargetNode((GameNode)allNodes.get((String)answers.find("solution", occur).attributes.get("t_id")));
				//tmpNode.addSolution(new Solution(childContentByName(answers, "solution", occur[0]), (GameNode)allNodes.get((String)answers.find("solution", occur).attributes.get("t_id"))));
			}
			if(answers.find("solution", occur).attributes.get("malus") != null)
			{
				int malus;
	    		String str = answers.find("solution", occur).attributes.get("malus").toString();
	    		malus = Integer.parseInt(str);
	    		
	    		tmpSolution.setMalus(malus);
				//tmpNode.addSolution(new Solution(childContentByName(answers, "solution", occur[0]), malus));
			}
			if(answers.find("solution", occur).attributes.get("source") != null)
			{
				tmpSolution.setSourceFile(answers.find("solution", occur).attributes.get("source").toString());
			}
			
			tmpNode.addSolution(tmpSolution);
			occur[0]++;
		}
    }
    
    public static void makeGameNode(Node xmlNode, Adventure adv, Hashtable allNodes)
    {
    	int occur[] = {1};
    	GameNode tmpNode = new GameNode(killTabs(childContentByName(xmlNode, "task")));
    	
    	if(xmlNode.attributes.containsKey("id"))
    	{
    		tmpNode.setId((String)xmlNode.attributes.get("id"));
    	}
    	else
    	{
    		System.out.println("Node id missing!");
    	}
    	
    	if(xmlNode.attributes.containsKey("type"))
    	{
    		if(xmlNode.attributes.get("type").equals("start"))
        	{
        		tmpNode.setStartNode();
        	}
    		else if(xmlNode.attributes.get("type").equals("end"))
        	{
    			tmpNode.setEndNode();
        	}
    	}
    	
    	Node task = xmlNode.find("task", occur);
    	
    	//System.out.println(task.attributes.get("value").toString());
    	if(task.attributes.containsKey("value"))
    	{
	    	try
	    	{
	    		int score;
	    		String str = task.attributes.get("value").toString();
	    		score = Integer.parseInt(str);
	    		
	    		//int score = ((Integer)(Object)task.attributes.get("value")).intValue();
	    		System.out.println(score);
	    		tmpNode.setMaxScore(score);
	    	}
	    	catch(Exception e)
	        {
	    		System.out.println("Problem reading task score.");
	        }
    	}
    	
    	if(task.attributes.containsKey("type"))
    	{
    		if(task.attributes.get("type").equals("text_selection"))
    		{
    			tmpNode.setTaskType(0);
    		}
    		else if(task.attributes.get("type").equals("text_answer"))
    		{
    			tmpNode.setTaskType(1);
    		}
    		else if(task.attributes.get("type").equals("image_selection"))
    		{
    			tmpNode.setTaskType(3);	
    		}
    		else if(task.attributes.get("type").equals("description_text"))
    		{
    			tmpNode.setTaskType(4);	
    		} 
    		else if(task.attributes.get("type").equals("descision_point"))
    		{
    			tmpNode.setTaskType(5);	
    		}
    		else if(task.attributes.get("type").equals("end_point"))
    		{
    			tmpNode.setTaskType(6);	
    		}                	               		
    		else
    		{
    			System.out.println("Error: A game node implements an invalid task-type: " + task.attributes.get("type").toString());
    		}
    	}

    	if(task.attributes.containsKey("medium")){
	    	String str = task.attributes.get("medium").toString();
	    	tmpNode.setMedium(str);        
        }

    	if(task.attributes.containsKey("hint")){
	    	String str = task.attributes.get("hint").toString();
	    	tmpNode.setHint(str.replace('_', ' '));        
        }
    	
/*        
        Node medium = xmlNode.find("medium", occur);

    	if(medium.attributes.containsKey("src")){
	    	String str = medium.attributes.get("src").toString();
	    	tmpNode.setMedium(str);
        }
*/    	
    	//System.out.println(tmpNode.getid());
		
		adv.addNode(tmpNode);
		
		allNodes.put(tmpNode.getid(), tmpNode);
    }
    
    /**
     * Creates a hardcoded adventure for testing purposes.
     * Loads nothing from the harddisk.
     */
    public static void createDummyAdventure(Adventure dummy) {
    	dummy.setTitle("The Crazy Schnitzelhunt");
		
    	GameNode larHom = new GameNode("At Larry's Home - Find a way out", GameNode.TEXT_SELECTION, 10);
    	GameNode street = new GameNode("On the street - where to go now?", GameNode.TEXT_SELECTION, 8);
    	GameNode toilet = new GameNode("In the toilet. Where is the exit?", GameNode.TEXT_SELECTION, 20);
    	GameNode hogwards = new GameNode("You find yourself at Hogwards.\n\nWhat is the name of the famous headmaster?", GameNode.TEXT_ANSWER, 30);
    	GameNode sky = new GameNode("There are some clouds in the sky.\nSelect the animal with claws!", GameNode.IMAGE_SELECTION, 5);
		GameNode bed = new GameNode("You went sleeping. Bye bye.", GameNode.TEXT_SELECTION);
		GameNode toilet_drinker_info = new GameNode("You got a bad breath.", GameNode.TEXT_SELECTION);
		
		bed.setEndNode();
		larHom.setStartNode();
		
		larHom.addSolution(new Solution("Visit the toilet", toilet));
		larHom.addSolution(new Solution("Sit on the sofa", 4));
		larHom.addSolution(new Solution("Go to bed.", bed));
		larHom.addSolution(new Solution("Go through the front door", street));
		dummy.addNode(larHom);
		
		street.addSolution(new Solution("Walk in a circle", 2));
		street.addSolution(new Solution("Look at the sky", sky));
		street.addSolution(new Solution("Sleep on the street", 5));
		street.addSolution(new Solution("Go home", larHom));
		dummy.addNode(street);
		
		toilet.addSolution(new Solution("Drink from the toilet", 12));
		toilet.addSolution(new Solution("Push the light switch", 1));
		toilet.addSolution(new Solution("Go through the mirror", hogwards));
		dummy.addNode(toilet);
		
		hogwards.addSolution(new Solution("Albus Dumbledore", larHom));
		hogwards.setStandardMalus(7);
    	dummy.addNode(hogwards);
    	
    	sky.addSolution(new Solution("cat","cat.png", larHom));
    	sky.addSolution(new Solution("sheep","sheep.png", 4));
    	dummy.addNode(sky);
    }
}